package com.cnap.service.impl;

import cn.hutool.core.io.FileUtil;
import com.cnap.CnapApplicationTests;
import com.cnap.db.entity.ApplicationPO;
import com.cnap.db.entity.IndicatorPO;
import com.cnap.db.mapper.ApplicationMapper;
import com.cnap.model.application.ApplicationDTO;
import com.cnap.model.application.ApplicationLabel;
import com.cnap.model.application.ApplicationVO;
import com.cnap.model.application.CategoryEnum;
import com.cnap.model.application.CategoryTypeEnum;
import com.cnap.model.application.QueryApplicationParam;
import com.cnap.model.application.UpdateApplicationParam;
import com.cnap.model.common.PageResult;
import com.cnap.model.exception.JsonException;
import com.cnap.model.file.FileInitReq;
import com.cnap.model.indicator.IndicatorTypeEnum;
import com.cnap.model.schedule.MicroServiceVO;
import com.cnap.model.schedule.StrategyStatusEnum;
import com.cnap.service.ApplicationService;
import com.cnap.service.FileService;
import com.cnap.service.IndicatorService;
import com.cnap.service.MicroSvcService;
import com.cnap.service.ProgressService;
import com.cnap.utils.JsonUtil;
import com.cnap.utils.TokenUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <类文件描述>
 *
 * @author xc
 **/
@Transactional
class ApplicationServiceImplTest extends CnapApplicationTests {

    @Autowired
    private ApplicationMapper applicationMapper;
    @Autowired
    private ApplicationService applicationService;

    @MockBean
    private FileService fileServiceMock;
    @MockBean
    private ProgressService progressServiceMock;
    @MockBean
    private IndicatorService indicatorServiceMock;
    @MockBean
    private MicroSvcService microSvcServiceMock;

    public void init() {
        ApplicationPO applicationPO = new ApplicationPO();
        applicationPO.setId("1");
        applicationPO.setLabel(new ApplicationLabel());
        applicationPO.setSize("300MB");
        applicationPO.setCategory(CategoryEnum.CATEGORY_AI.getValue());
        applicationPO.setName("AI质检123");
        applicationPO.setUserName("admin");
        applicationPO.setVersion("1.0");
        applicationPO.setDescription("des");
        applicationPO.setUpdateTime(LocalDateTime.now());
        applicationPO.setStatus(1);
        applicationPO.setType(CategoryTypeEnum.AI_STATIC_TRAIN.getValue());

        ApplicationPO applicationPO1 = new ApplicationPO();
        applicationPO1.setId("2");
        applicationPO1.setLabel(new ApplicationLabel());
        applicationPO1.setSize("300MB");
        applicationPO1.setCategory(CategoryEnum.CATEGORY_BIG_DATA.getValue());
        applicationPO1.setName("测试");
        applicationPO1.setUserName("xc");
        applicationPO1.setVersion("1.1");
        applicationPO1.setDescription("asdasddes");
        applicationPO1.setUpdateTime(LocalDateTime.now());
        applicationPO1.setStatus(1);
        applicationPO1.setType(CategoryTypeEnum.BIG_DATA_REALTIME.getValue());

        int s = applicationMapper.insertApplication(applicationPO);
        applicationMapper.insertApplication(applicationPO1);
    }

    @Test
    void findByPage() {
        init();
        //Mockito.when(userServiceMock.checkUserHasAdminRole()).thenReturn(true);
        QueryApplicationParam param = new QueryApplicationParam();
        param.setPageSize(10);
        param.setPageNum(1);
        param.setCategory("");
        param.setApplicationName("AI质检123");
        PageResult<ApplicationVO> result = applicationService.findByPage(param);

        Assertions.assertEquals(1, result.getData().size());
    }

    @Test
    void uploadApplication() {
        String applicationDTOStr = "{\n" +
                "\t\"applicationName\": \"test-label-2\",\n" +
                "\t\"category\": \"AI\",\n" +
                "\t\"type\": \"动态训练\",\n" +
                "\t\"version\": \"V1.2\",\n" +
                "\t\"description\": \"测试2个镜像\",\n" +
                "\t\"userName\": \"admin\",\n" +
                "\t\"label\": {\n" +
                "\t\t\"objectScene\": [\n" +
                "\t\t\t\"智能运维\",\n" +
                "\t\t\t\"智能推荐\",\n" +
                "\t\t\t\"人脸识别\"\n" +
                "\t\t],\n" +
                "\t\t\"technology\": [\n" +
                "\t\t\t\"模型推理\",\n" +
                "\t\t\t\"Caffe\",\n" +
                "\t\t\t\"OpenCV\",\n" +
                "\t\t\t\"飞浆\"\n" +
                "\t\t]\n" +
                "\t},\n" +
                "\t\"fileInfo\": {\n" +
                "\t\t\"name\": \"right-2.zip\",\n" +
                "\t\t\"md5\": \"72598d3b4f9d26e68b4e00c5b5344297\",\n" +
                "\t\t\"totalSize\": 1261604,\n" +
                "\t\t\"patchNums\": 3\n" +
                "\t}\n" +
                "}";
        ApplicationDTO applicationDTO = JsonUtil.jsonStrToObject(applicationDTOStr, ApplicationDTO.class);
        Assertions.assertNotNull(applicationDTO);

        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(true);
        Mockito.when(indicatorServiceMock.batchInsertIndicatorCases(Mockito.anyList())).thenReturn(true);

        String result = applicationService.uploadApplication(applicationDTO);

        Assertions.assertNotNull(result);
    }

    @Test
    void uploadApplicationWithSameAppException() {
        init();
        String applicationDTOStr = "{\n" +
                "\t\"applicationName\": \"AI质检123\",\n" +
                "\t\"category\": \"AI\",\n" +
                "\t\"type\": \"动态训练\",\n" +
                "\t\"version\": \"1.0\",\n" +
                "\t\"description\": \"测试2个镜像\",\n" +
                "\t\"userName\": \"admin\",\n" +
                "\t\"label\": {\n" +
                "\t\t\"objectScene\": [\n" +
                "\t\t\t\"智能运维\",\n" +
                "\t\t\t\"智能推荐\",\n" +
                "\t\t\t\"人脸识别\"\n" +
                "\t\t],\n" +
                "\t\t\"technology\": [\n" +
                "\t\t\t\"模型推理\",\n" +
                "\t\t\t\"Caffe\",\n" +
                "\t\t\t\"OpenCV\",\n" +
                "\t\t\t\"飞浆\"\n" +
                "\t\t]\n" +
                "\t},\n" +
                "\t\"fileInfo\": {\n" +
                "\t\t\"name\": \"right-2.zip\",\n" +
                "\t\t\"md5\": \"72598d3b4f9d26e68b4e00c5b5344297\",\n" +
                "\t\t\"totalSize\": 1261604,\n" +
                "\t\t\"patchNums\": 3\n" +
                "\t}\n" +
                "}";
        ApplicationDTO applicationDTO = JsonUtil.jsonStrToObject(applicationDTOStr, ApplicationDTO.class);
        Assertions.assertNotNull(applicationDTO);

        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(true);

        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(true);

        Assertions.assertThrows(JsonException.class, () -> {
            String result = applicationService.uploadApplication(applicationDTO);
        });
    }

    @Test
    void uploadApplicationWithDbAppException() {
        init();
        String applicationDTOStr = "{\n" +
                "\t\"applicationName\": \"asda123\",\n" +
                "\t\"category\": \"AI\",\n" +
                "\t\"type\": \"动态训练\",\n" +
                "\t\"version\": \"1.0\",\n" +
                "\t\"description\": \"测试2个镜像\",\n" +
                "\t\"userName\": \"xc\",\n" +
                "\t\"label\": {\n" +
                "\t\t\"objectScene\": [\n" +
                "\t\t\t\"智能运维\",\n" +
                "\t\t\t\"智能推荐\",\n" +
                "\t\t\t\"人脸识别\"\n" +
                "\t\t],\n" +
                "\t\t\"technology\": [\n" +
                "\t\t\t\"模型推理\",\n" +
                "\t\t\t\"Caffe\",\n" +
                "\t\t\t\"OpenCV\",\n" +
                "\t\t\t\"飞浆\"\n" +
                "\t\t]\n" +
                "\t},\n" +
                "\t\"fileInfo\": {\n" +
                "\t\t\"name\": \"right-2.zip\",\n" +
                "\t\t\"md5\": \"72598d3b4f9d26e68b4e00c5b5344297\",\n" +
                "\t\t\"totalSize\": 1261604,\n" +
                "\t\t\"patchNums\": 3\n" +
                "\t}\n" +
                "}";
        ApplicationDTO applicationDTO = JsonUtil.jsonStrToObject(applicationDTOStr, ApplicationDTO.class);
        Assertions.assertNotNull(applicationDTO);
        applicationDTO.setApplicationName(null);
        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(true);

        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(true);

        Assertions.assertDoesNotThrow(() -> {
            String result = applicationService.uploadApplication(applicationDTO);
        });
    }


    @Test
    void uploadApplicationWithProgressAppException() {
        init();
        String applicationDTOStr = "{\n" +
                "\t\"applicationName\": \"asda123\",\n" +
                "\t\"category\": \"AI\",\n" +
                "\t\"type\": \"动态训练\",\n" +
                "\t\"version\": \"1.0\",\n" +
                "\t\"description\": \"测试2个镜像\",\n" +
                "\t\"userName\": \"xc\",\n" +
                "\t\"label\": {\n" +
                "\t\t\"objectScene\": [\n" +
                "\t\t\t\"智能运维\",\n" +
                "\t\t\t\"智能推荐\",\n" +
                "\t\t\t\"人脸识别\"\n" +
                "\t\t],\n" +
                "\t\t\"technology\": [\n" +
                "\t\t\t\"模型推理\",\n" +
                "\t\t\t\"Caffe\",\n" +
                "\t\t\t\"OpenCV\",\n" +
                "\t\t\t\"飞浆\"\n" +
                "\t\t]\n" +
                "\t},\n" +
                "\t\"fileInfo\": {\n" +
                "\t\t\"name\": \"right-2.zip\",\n" +
                "\t\t\"md5\": \"72598d3b4f9d26e68b4e00c5b5344297\",\n" +
                "\t\t\"totalSize\": 1261604,\n" +
                "\t\t\"patchNums\": 3\n" +
                "\t}\n" +
                "}";
        ApplicationDTO applicationDTO = JsonUtil.jsonStrToObject(applicationDTOStr, ApplicationDTO.class);
        Assertions.assertNotNull(applicationDTO);

        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(true);

        Mockito.when(fileServiceMock.initFileInfo(Mockito.any(), Mockito.any())).thenReturn("testid");
        Mockito.when(progressServiceMock.initProgress(Mockito.any())).thenReturn(false);

        Assertions.assertThrows(JsonException.class, () -> {
            String result = applicationService.uploadApplication(applicationDTO);
        });
    }

    @Test
    void updateApplicationWithException() {
        init();
        UpdateApplicationParam param = new UpdateApplicationParam();
        param.setId("123");
        param.setDescription("des");
        Assertions.assertThrows(JsonException.class, () -> {
            applicationService.updateApplication(param);
        });
    }

    @Test
    void updateApplication() {
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMDE4NDEsInN1YiI6ImFkbWluIiwiaWF0IjoxNjYzMjg3NDQxNTU1fQ.O013QUhwbqD_12hf_SdIuPxIHOvolrXfSGJVBlrZVRo");

        Mockito.when(indicatorServiceMock.deleteIndicatorCaseByAppId(Mockito.anyString())).thenReturn(true);
        Mockito.when(indicatorServiceMock.batchInsertIndicatorCases(Mockito.anyList())).thenReturn(true);
        init();
        UpdateApplicationParam param = new UpdateApplicationParam();
        param.setId("1");
        param.setDescription("des");
        param.setCategory(CategoryEnum.CATEGORY_BIG_DATA.getValue());
        applicationService.updateApplication(param);

        ApplicationPO applicationPO = applicationMapper.selectById("1");

        Assertions.assertEquals("des", applicationPO.getDescription());
    }

    @Test
    void deleteOtherResourcesByApplicationId() {
        Mockito.when(fileServiceMock.deleteFileInfoAndPatchInfoById("1")).thenReturn(true);
        Assertions.assertDoesNotThrow(() -> {
            applicationService.deleteOtherUploadResourcesByApplicationId("1");
        });
    }

    @Test
    void findByPageForSplit() {
        init();
        //Mockito.when(userServiceMock.checkUserHasAdminRole()).thenReturn(true);
        QueryApplicationParam param = new QueryApplicationParam();
        param.setPageSize(10);
        param.setPageNum(1);
        param.setCategory("AI");
        param.setApplicationName("");
        applicationMapper.updateApplicationStatusById("1", 2);
        PageResult<ApplicationVO> result = applicationService.findByPageForSplit(param);

        Assertions.assertTrue(result.getData().size() >= 1);
    }

    @Test
    void deleteAllUploadResourcesByApplicationId() {
        init();
        Assertions.assertDoesNotThrow(() -> {
            applicationService.deleteAllUploadResourcesByApplicationId("1");
        });
        ApplicationPO applicationPO = applicationMapper.selectById("1");

        Assertions.assertNull(applicationPO);
    }

    @Test
    void updateApplicationStatus() {
        init();

        applicationService.updateApplicationStatus("1", 3);

        ApplicationPO applicationPO = applicationService.selectByAppId("1");

        Assertions.assertEquals(3, applicationPO.getStatus());
    }

    @Test
    void selectByAppId() {
        init();

        ApplicationPO applicationPO = applicationService.selectByAppId("1");

        Assertions.assertEquals("AI质检123", applicationPO.getName());
    }

    @Test
    void deleteApplicationByIdWithNoPermission() {
        init();
        // 非admin
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMjYxMjUsInN1YiI6InhjIiwiaWF0IjoxNjYzMzExNzI1NjkyfQ.qKs5JLBG9qg18apuk2OeL6_r9GqAw6Pa_P8WEnfDOE4");
        Assertions.assertThrows(JsonException.class, () -> {
            applicationService.deleteApplicationById("2");
        });
    }

    @Test
    void deleteApplicationByIdWithServiceRunning() {
        init();
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMDE4NDEsInN1YiI6ImFkbWluIiwiaWF0IjoxNjYzMjg3NDQxNTU1fQ.O013QUhwbqD_12hf_SdIuPxIHOvolrXfSGJVBlrZVRo");
        MicroServiceVO po = new MicroServiceVO();
        po.setStatus(StrategyStatusEnum.APPLIED.getStatus() + "");
        List<MicroServiceVO> microServicePOS = Collections.singletonList(po);
        Mockito.when(microSvcServiceMock.selectMicroServicesByAppId(Mockito.any())).thenReturn(microServicePOS);
        Assertions.assertThrows(JsonException.class, () -> {
            applicationService.deleteApplicationById("1");
        });
    }

    @Test
    void deleteApplicationByIdWithStatusPaused() {
        init();
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMDE4NDEsInN1YiI6ImFkbWluIiwiaWF0IjoxNjYzMjg3NDQxNTU1fQ.O013QUhwbqD_12hf_SdIuPxIHOvolrXfSGJVBlrZVRo");
        MicroServiceVO po = new MicroServiceVO();
        po.setStatus(StrategyStatusEnum.PAUSED.getStatus() + "");
        List<MicroServiceVO> microServicePOS = Collections.singletonList(po);
        Mockito.when(microSvcServiceMock.selectMicroServicesByAppId(Mockito.any())).thenReturn(microServicePOS);
        Assertions.assertThrows(JsonException.class, () -> {
            applicationService.deleteApplicationById("1");
        });
    }

    @Test
    void deleteApplicationByIdWithStatusStarting() {
        init();
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMDE4NDEsInN1YiI6ImFkbWluIiwiaWF0IjoxNjYzMjg3NDQxNTU1fQ.O013QUhwbqD_12hf_SdIuPxIHOvolrXfSGJVBlrZVRo");
        MicroServiceVO po = new MicroServiceVO();
        po.setStatus(StrategyStatusEnum.STARTING.getStatus() + "");
        List<MicroServiceVO> microServicePOS = Collections.singletonList(po);
        Mockito.when(microSvcServiceMock.selectMicroServicesByAppId(Mockito.any())).thenReturn(microServicePOS);
        Assertions.assertThrows(JsonException.class, () -> {
            applicationService.deleteApplicationById("1");
        });
    }

    @Test
    void deleteApplicationByIdWithHarborFail() {
        init();
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMDE4NDEsInN1YiI6ImFkbWluIiwiaWF0IjoxNjYzMjg3NDQxNTU1fQ.O013QUhwbqD_12hf_SdIuPxIHOvolrXfSGJVBlrZVRo");
        MicroServiceVO po = new MicroServiceVO();
        po.setStatus(StrategyStatusEnum.INIT.getStatus() + "");
        List<MicroServiceVO> microServicePOS = Collections.singletonList(po);
        Mockito.when(microSvcServiceMock.selectMicroServicesByAppId(Mockito.any())).thenReturn(microServicePOS);
        Mockito.when(microSvcServiceMock.deleteMicroServiceImagesWithAppId("1")).thenReturn(false);
        boolean res = applicationService.deleteApplicationById("1");
        Assertions.assertFalse(res);
    }

    @Test
    void deleteApplicationById() {
        init();
        TokenUtils.setTOKEN("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NjMzMDE4NDEsInN1YiI6ImFkbWluIiwiaWF0IjoxNjYzMjg3NDQxNTU1fQ.O013QUhwbqD_12hf_SdIuPxIHOvolrXfSGJVBlrZVRo");
        MicroServiceVO po = new MicroServiceVO();
        po.setStatus(StrategyStatusEnum.INIT.getStatus() + "");
        List<MicroServiceVO> microServicePOS = Collections.singletonList(po);
        Mockito.when(microSvcServiceMock.selectMicroServicesByAppId(Mockito.any())).thenReturn(microServicePOS);
        Mockito.when(microSvcServiceMock.deleteMicroServiceImagesWithAppId(Mockito.any())).thenReturn(true);
        Mockito.doNothing().when(microSvcServiceMock).deleteMicroServiceAndStrategyWithAppId(Mockito.any());
        Assertions.assertDoesNotThrow(()->{
            applicationService.deleteApplicationById("1");
        });
    }

    @Test
    void testDeleteUnzipFileAndDbInfoQWithDeleteFail() {
        fileUtilMockedStatic.when(() -> FileUtil.del(Mockito.anyString())).thenReturn(false);
        Assertions.assertDoesNotThrow(()->{
            applicationService.deleteUnzipFileAndDbInfo("appId");
        });
    }

    @Test
    void testDeleteUnzipFileAndDbInfoQWithDeleteFail2() {
        fileUtilMockedStatic.when(() -> FileUtil.del(Mockito.anyString())).thenReturn(false);
        Mockito.when(microSvcServiceMock.deleteMicroServiceImagesWithAppId("appId")).thenReturn(false);
        Assertions.assertDoesNotThrow(() -> {
            applicationService.deleteUnzipFileAndDbInfo("appId");
        });
    }

    @Test
    void testDeleteUnzipFileAndDbInfoQWithPathUnexist() {
        fileUtilMockedStatic.when(() -> FileUtil.exist(Mockito.anyString())).thenReturn(true);
        fileUtilMockedStatic.when(() -> FileUtil.del(Mockito.anyString())).thenReturn(false);
        Mockito.when(microSvcServiceMock.deleteMicroServiceImagesWithAppId("appId")).thenReturn(false);
        Assertions.assertDoesNotThrow(() -> {
            applicationService.deleteUnzipFileAndDbInfo("appId");
        });
    }

    @Test
    void saveApplicationWithUploadedStatus() {
        ApplicationDTO applicationDTO = new ApplicationDTO();
        applicationDTO.setApplicationName("appName");
        applicationDTO.setType(CategoryTypeEnum.AI_STATIC_TRAIN.getValue());
        applicationDTO.setLabel(new ApplicationLabel());
        applicationDTO.setDescription("des");
        applicationDTO.setVersion("v1");
        applicationDTO.setUserName("admin");
        applicationDTO.setCategory(CategoryEnum.CATEGORY_AI.getValue());
        FileInitReq req = new FileInitReq();
        req.setTotalSize(100);
        applicationDTO.setFileInitReq(req);

        List<IndicatorPO> indicatorPOS = new ArrayList<>();
        IndicatorPO po = new IndicatorPO();
        po.setUnit("unit");
        po.setValue("value");
        po.setKey("key");
        po.setId("qwer");
        po.setIndicatorType(IndicatorTypeEnum.CAL.getValue());
        po.setCategory(CategoryEnum.CATEGORY_AI.getValue());
        po.setType(CategoryTypeEnum.AI_STATIC_TRAIN.getValue());
        indicatorPOS.add(po);
        Mockito.when(indicatorServiceMock.getIndicatorByCategoryAndType(CategoryEnum.CATEGORY_AI.getValue(),
                        CategoryTypeEnum.AI_STATIC_TRAIN.getValue())).thenReturn(indicatorPOS);
        Mockito.when(indicatorServiceMock.batchInsertIndicatorCases(Mockito.anyList())).thenReturn(true);
        Assertions.assertDoesNotThrow(()->{
            applicationService.saveApplicationWithUploadedStatus(applicationDTO, "appId");
        });
    }
}